package net.qiqbframework.config;


import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.common.Registration;
import net.qiqbframework.lifecycle.Phase;
import net.qiqbframework.modelling.command.*;

import java.util.ArrayList;
import java.util.List;


/**
 * 配置聚合运行所需的所有组件
 */
@Slf4j
public class CommandConfigurer<C, A> implements CommandConfiguration<C, A> {

    private final Class<C> commandType;

    private final Class<A> aggregateType;

    private ComponentHolder<InnerAnnotationCommandHandler<C, A>> commandHandler;


    private final ComponentHolder<CommandTargetResolver> commandTargetResolver;


    private final List<Registration> registrations = new ArrayList<>();

    private Configuration parent;

    public static <C, A> CommandConfigurer<C, A> defaultConfiguration(Class<C> commandType, Class<A> aggregateType) {
        return new CommandConfigurer<>(commandType, aggregateType);
    }

    protected CommandConfigurer(Class<C> commandType, Class<A> aggregateType) {
        this.commandType = commandType;

        this.aggregateType = aggregateType;


        commandTargetResolver = new ComponentHolder<>(
                () -> parent, name("commandTargetResolver"),
                c -> c.getComponent(
                        CommandTargetResolver.class,
                        () -> AnnotationCommandTargetResolver.builder().build()
                )
        );

    }


    private String name(String prefix) {
        return prefix + "<" + commandType.getSimpleName() + ">";
    }


    @Override
    public void initialize(Configuration config) {
        final AggregateConfiguration<A> aggregateConfiguration = config.aggregateConfiguration(aggregateType);
        commandHandler = new ComponentHolder<>(
                () -> parent, name("aggregateCommandHandler"),
                c -> InnerAnnotationCommandHandlerBuilder.<C, A>builder()
                        .repository(aggregateConfiguration.repository())
                        .javersBuilder(c.aggregateJaversBuilder())
                        .commandTargetResolver(commandTargetResolver.get())
                        .aggregateModel(aggregateConfiguration.aggregateModel())
                        .commandType(commandType)
                        .parameterResolverFactory(c.parameterResolverFactory())
                        .handlerDefinition(c.handlerDefinition(aggregateType))
                        .addAggregateHandlingMonitor(c.getComponent(AggregateHandlingMonitor.class))
                        .aggregateRootSerializer(c.aggregateSerializer())
                        .build()
        );

        parent = config;
        parent.onStart(
                Phase.LOCAL_MESSAGE_HANDLER_REGISTRATIONS,
                () -> {
                    registrations.add(commandHandler.get().subscribe(parent.commandBus()));
                }
        );
        parent.onShutdown(
                Phase.LOCAL_MESSAGE_HANDLER_REGISTRATIONS,
                () -> {
                    registrations.forEach(Registration::cancel);
                    registrations.clear();
                }
        );


    }

    @Override
    public Class<A> aggregateType() {
        return aggregateType;
    }

    @Override
    public Class<C> commandType() {
        return commandType;
    }


}
